
#include <iostream>

#include "../headers/Worker.h"

using namespace std;

Worker::Worker(int id, Mailbox* mailer, vector<int>* neighbours) :
	table(id), myId(id), mailer(mailer), neighbours(*neighbours), shouldRevive(false), busy(true), alive(true)
{
}

Worker::~Worker()
{
}

void Worker::run()
{
	while(true){
		busy=true;
		vector<RoutingTable*> neighbor_tables;
		Message* temp;

		if(shouldRevive) {
			shouldRevive=false;
			cout<<"Reviving worker "<<myId<<endl;
			table.reset();
			transmitTableToNeighbours();
			alive=true;
		}

		//cout << "worker "<< myId <<" checking msgs..."<<endl;
		// receieve all messages
		while(recv((void**)&temp)) {
			//cout << "worker "<< myId << " received "<< *temp <<endl;
			switch(temp->msgType()) {
				case ROUTING_MSG:
					if(alive)
						neighbor_tables.push_back(((RoutingMessage*)temp)->table);
					break;

				case SYSTEM_MSG:
					if(alive) {
						SystemMessage* msg=(SystemMessage*)temp;
						if (msg->destination == myId) {
							//cout << "[" << *msg << "] has reached it's destination after " << msg->steps << " steps" << endl;
							cout << myId << " received \"" << msg->content << "\" from " << msg->origin << " after "<<msg->steps << " steps" <<endl;
							//todo: make the shell print it
							//send(new SystemMessage(myId, 0, str));
						}
						else {
							//send(new SystemMessage(myId, this->table.nextHopFor(msg->destination), msg->destination, msg->content, msg->steps+1));
							if(this->table.nextHopFor(msg->destination)!=UNREACHABLE) {
								send(new SystemMessage(msg, this->table.nextHopFor(msg->destination)));
								cout << myId <<" is sending \""<<msg->content <<"\" to "<<msg->destination<<" through "<< this->table.nextHopFor(msg->destination)<<endl;
							}
							else
								cout << "you're an idiot"<<endl;
						}
					}
					break;
			}

			delete temp;
		}
		//cout << "worker "<< myId <<"'s emptied his inbox."<<endl;

		//update my table with the neighbor_tables that were recieved this round.
		if(!neighbor_tables.empty() && this->table.updateWith(neighbor_tables)) {
			//cout << "worker "<<myId << " has updated his routing table"<<endl;//, which is now "<<endl<<table<<endl;
			transmitTableToNeighbours();
		}

		//cout << "worker "<< myId <<" yields."<<endl;
		if(!shouldRevive) {
			busy = false;
			//cout << "worker "<<myId << " yields." <<endl;
			yield();
		}
	}

}

void Worker::transmitTableToNeighbours(){
	cout << "worker "<< myId <<" sending RT-messages to all neighbours..."<<endl;
	for (vector<int>::iterator  it=neighbours.begin() ; it < neighbours.end(); it++ ){
	    send(new RoutingMessage(myId, *it, &table));
	}
}

/*
 * pass to mailer
 */
bool Worker::studentSend(void *args)
{
	Message* msg=(Message *)args;
	//cout << "worker "<<myId<<" studentSend is sending the message: " << *msg << endl;
	while(!mailer->submitMessage(msg)){
		yield();
	}

	return true;
}

/*
 */
bool Worker::studentRecv(void **args)
{
	if(!hasNewMessage())
		return false;

	*args = popMessage();

	return true;
}

void Worker::revive(){
	initialize();
	shouldRevive=true;
	busy=true;
	//setQuanta(getQuanta()); // this will wake a yielded thread
}

void Worker::initialize(){
	clearMailbox();
	table.reset();
}

void Worker::kill(){
	alive=false;
	initialize();
}
